package com.zmj.demo.controller;

import cn.hutool.json.JSONUtil;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import com.zmj.demo.restclient.AuthClient;
import com.zmj.demo.service.EsOperate;
import com.zmj.demo.service.impl.HelloServiceImpl;
import com.zmj.framework.circuitBreaker.RateLimiterUtil;
import com.zmj.framework.exception.server.ServerException;
import com.zmj.framework.request.PageRequest;
import com.zmj.framework.response.Result;
import com.zmj.framework.circuitBreaker.CircuitBreakerUtil;
import io.github.resilience4j.circuitbreaker.CallNotPermittedException;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
import io.github.resilience4j.timelimiter.TimeLimiter;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.vavr.CheckedFunction0;
import io.vavr.control.Try;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeoutException;

@RestController
@Api(tags = {"hello"})
@RequestMapping("/v1/hello")
@Slf4j
public class HelloController {

    @Autowired
    HelloServiceImpl helloService;

    @Autowired
    AuthClient authClient;

    @Autowired
    EsOperate esOperate;

    @Autowired
    private TimeLimiter timeLimiter;

    @Autowired
    private CircuitBreakerRegistry circuitBreakerRegistry;

    @ApiOperation(value = "hello world")
    @GetMapping(value = "")
    @ResponseBody
    public Result hello() {
        return Result.success();
    }

    @ApiOperation(value = "熔断器之超时")
    @GetMapping(value = "timeOut")
    @ResponseBody
    public Result timeOut() {
        try {
            Result result = timeLimiter.executeFutureSupplier(
                    () -> CompletableFuture.supplyAsync(() ->
                            helloService.testTimeOut()
                    ));
            return result;
        } catch (Exception exception) {
            if (exception instanceof TimeoutException) {
                //TODO 超时逻辑处理
                return Result.fail("超时：" + exception.getMessage());
            }
            return Result.fail("异常：" + exception.getMessage());
        }
    }

    @GetMapping(value = "testClientError")
    public Result testRestClientError() {
        return authClient.getException();
    }


    @GetMapping(value = "testES")
    public Result testES() {

//        boolean test = esOperate.existsIndex("test");

        List<Map<String, String>> list = new ArrayList<>();

        list.add(Map.of("id", "1", "name", "www1"));
        list.add(Map.of("id", "2", "name", "www2"));
        list.add(Map.of("id", "3", "name", "www3"));

        String json = JSONUtil.parseArray(list).toString();
        log.info("json {}", json);
        PageRequest pageRequest = new PageRequest();
//        esOperate.insertIndex("test",json);
        List<Map<String, Object>> test= esOperate.query(pageRequest, "test");
        return Result.success(test);
    }

    @ApiOperation(value = "熔断器执行过程")
    @GetMapping(value = "testCircuitBreaker")
    public Result testCircuitBreaker() {
        // 通过注册器获取熔断器的实例
        CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("simple");
        CircuitBreakerUtil.getCircuitBreakerStatus("执行开始前：", circuitBreaker);
        // 使用熔断器包装连接器的方法
        CheckedFunction0<Result> checkedFunction0 = CircuitBreaker.decorateCheckedSupplier(circuitBreaker, helloService::testCircuitBreaker);

        // 使用Try.of().recover()调用并进行降级处理 降级逻辑自行实现
        Try<Result> result = Try.of(checkedFunction0).
                recover(CallNotPermittedException.class, throwable -> {
                    log.info("熔断器已经打开，拒绝访问被保护方法~");
                    CircuitBreakerUtil.getCircuitBreakerStatus("熔断器打开中:", circuitBreaker);
                    //TODO 熔断器打开处理逻辑
                    return Result.fail("熔断器打开中:" + circuitBreaker.getName());
                })
                .recover(throwable -> {
                    log.info(throwable.getLocalizedMessage() + ",方法被降级了~~");
                    CircuitBreakerUtil.getCircuitBreakerStatus("降级方法中:", circuitBreaker);
                    //TODO 降级的方法处理逻辑
                    return Result.fail("降级方法中:" + circuitBreaker);
                });
        CircuitBreakerUtil.getCircuitBreakerStatus("执行结束后：", circuitBreaker);
        return result.get();
    }

    @ApiOperation(value = "普通的熔断器使用方式")
    @GetMapping(value = "testCircuitBreakerSimple")
    public Result testCircuitBreakerSimple() {
        // 通过注册器获取熔断器的实例
        CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("simple");
        try {
            return circuitBreaker.executeCheckedSupplier(helloService::testCircuitBreaker);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            return Result.fail(throwable.toString());
        }
    }

    @ApiOperation(value = "普通的熔断器使用方式")
    @GetMapping(value = "testCircuitBreakerSimpleAop")
    public Result testCircuitBreakerSimpleAop() throws InterruptedException, TimeoutException {
        CircuitBreakerUtil
                .getCircuitBreakerStatus("执行开始前：", circuitBreakerRegistry.circuitBreaker("simple"));
        Result result = helloService.testCircuitBreakerAop();
        CircuitBreakerUtil
                .getCircuitBreakerStatus("执行结束后：", circuitBreakerRegistry.circuitBreaker("simple"));
        return result;

    }

    @Autowired
    private RateLimiterRegistry rateLimiterRegistry;

    @ApiOperation(value = "令牌桶的aop使用方式")
    @GetMapping(value = "testRateLimiterSimpleAop")
    public Result testRateLimiterSimpleAop() throws InterruptedException, TimeoutException {
        Result result = helloService.testRateLimiterAop();
        RateLimiterUtil.getRateLimiterStatus("执行结束后：", rateLimiterRegistry.rateLimiter("simple"));
        return result;

    }

}
